package Sokoban;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Scanner;

import javax.imageio.ImageIO;



public class RunnableGetImage extends Canvas implements Runnable {
	
	Image offscr = null;

    Graphics offgr = null;
	private TileMap map;
	
	//private int screenWidth, screenHeight;
	public int TILE_SIZE; 
	BufferStrategy bs = null;
	Thread kicker = null;

	private boolean timeToQuit=false;
	public int positionShift=0;
	public double positionStep=0;
	
	public volatile static boolean begin=true;
	public boolean MOVE_BOTH=false;
	private int boulderToMove;
	
	private final static int LEFT_COLLISION = 1;
	private final static int RIGHT_COLLISION = 2;
	private final static int TOP_COLLISION = 3;
	private final static int BOTTOM_COLLISION = 4;
	
	public final static int MOVE_UP = 5;
	public final static int MOVE_RIGHT = 6;
	public final static int MOVE_DOWN = 7;
	public final static int MOVE_LEFT = 8;
	public int WHICH_WAY;
	
	static boolean completed = false;
	
	
	 
	RunnableGetImage(MapObject mapObject, int tile_size, BufferStrategy bs) throws IOException
	{
        this.bs = bs;
		this.map = mapObject.getMap();
		TILE_SIZE=tile_size;
		
	}
	
	void modifyLocation(float initialPosition, int WHICH_WAY, int positionShift, double positionStep, int boulderToMove) {
		
		if (WHICH_WAY == MOVE_UP){
			
		float currentPosition = map.getPlayer().getY();
		//System.out.println("Provisional position: " + positionToPixels(currentPosition));
		//System.out.println("boulderToMove= "+boulderToMove);
		if (currentPosition + positionStep > initialPosition + positionShift){
			if (boulderToMove>-1) 
			{
				MovingImage boulder = (MovingImage)map.getBoulders().get(boulderToMove);
				boulder.setY((float)(boulder.getY()+positionStep));
			}
		map.getPlayer().setY((float)(currentPosition+positionStep));
		//mozna zrobic z czasem i predkoscia
		}
		else {
			if (boulderToMove>-1) 
			{
				MovingImage boulder = (MovingImage)map.getBoulders().get(boulderToMove);
				boulder.setY((float)(initialPosition+positionShift+Math.signum(positionShift)));
			}
			map.getPlayer().setY(initialPosition+positionShift);
			timeToQuit=true;
		}
		
		}
		
		
		else if (WHICH_WAY == MOVE_DOWN){
			float currentPosition = map.getPlayer().getY();
			if (currentPosition + positionStep < initialPosition + positionShift){
				if (boulderToMove>-1) 
				{
					MovingImage boulder= (MovingImage)map.getBoulders().get(boulderToMove);
					boulder.setY((float)(boulder.getY()+positionStep));
				}
			map.getPlayer().setY((float)(currentPosition+positionStep));
			//mozna zrobic z czasem i predkoscia
			}
			else {
				if (boulderToMove>-1) 
				{
					MovingImage boulder = (MovingImage)map.getBoulders().get(boulderToMove);
					boulder.setY((float)(initialPosition+positionShift+Math.signum(positionShift)));
				}
				map.getPlayer().setY(initialPosition+positionShift);
				timeToQuit=true;
			}
			
			}
		else if (WHICH_WAY == MOVE_LEFT){
			float currentPosition = map.getPlayer().getX();
			if (currentPosition + positionStep > initialPosition + positionShift){
				if (boulderToMove>-1) 
				{
					MovingImage boulder = (MovingImage)map.getBoulders().get(boulderToMove);
					boulder.setX((float)(boulder.getX()+positionStep));
				}

			map.getPlayer().setX((float)(map.getPlayer().getX()+positionStep));
			//mozna zrobic z czasem i predkoscia
			}
			else {
				if (boulderToMove>-1) 
				{
					MovingImage boulder = (MovingImage)map.getBoulders().get(boulderToMove);
					boulder.setX((float)(initialPosition+positionShift+Math.signum(positionShift)));
				}
				map.getPlayer().setX(initialPosition+positionShift);
				timeToQuit=true;
			}
			
			}
		else if (WHICH_WAY == MOVE_RIGHT){
			float currentPosition = map.getPlayer().getX();
			if (currentPosition + positionStep < initialPosition + positionShift){
				
					if (boulderToMove>-1) 
					{
						MovingImage boulder = (MovingImage)map.getBoulders().get(boulderToMove);
						boulder.setX((float)(boulder.getX()+positionStep));
					}
			map.getPlayer().setX((float)(currentPosition+positionStep));
			//mozna zrobic z czasem i predkoscia
			}
			else {
				if (boulderToMove>-1) 
				{
					MovingImage boulder = (MovingImage)map.getBoulders().get(boulderToMove);
					boulder.setX((float)(initialPosition+positionShift+Math.signum(positionShift)));
				}
				map.getPlayer().setX(initialPosition+positionShift);
				timeToQuit=true;
			}
			}
    }
	
	
	void updateOffscreen(Graphics g) {
		
		/*if (completed) {
            g.setColor(new Color(0, 0, 0));
            g.drawString("Completed", 250, 200);
        }*/
				
		 for (int y=0; y < map.getHeight(); y++) { 
				
	            for (int x=0; x < map.getWidth(); x++) {
	                
	                
	                	
	                    
	                    	if (map.getTile(x, y)!= null){
	                    	g.drawImage(map.getTile(x,y),
	                    			tilesToPixels(x),
	                    			tilesToPixels(y),
	                    			TILE_SIZE,
	                    			TILE_SIZE,
	                    			null);
	                    	}
	            }
			}
			g.drawImage(map.getPlayerImage(), 
					positionToPixels(map.getPlayer().getX()), 
					positionToPixels(map.getPlayer().getY()),
					TILE_SIZE,
					TILE_SIZE,
					null);
			for (int i=0; i<map.getBoulders().size(); i++)
				
			g.drawImage(map.getBoulderImage(), 
					positionToPixels(((MovingImage)map.getBoulders().get(i)).getX()), 
					positionToPixels(((MovingImage)map.getBoulders().get(i)).getY()),
					TILE_SIZE,
					TILE_SIZE,
					null);
	
    }
	
	void sleep() {
        try {
            Thread.sleep(40); 
        } catch (InterruptedException ie) {
        }
    }
	
	public void stopRunning() {
		timeToQuit=true;
		}
	
public synchronized void moveUp() throws InterruptedException{
	
	begin=false;
	
	if (checkWallCollision(this, this.getMap().getPlayer(),TOP_COLLISION)) {
		begin=true;
        return;
    }
	if (checkBagCollision(this, TOP_COLLISION)){
		begin=true;	
		return;
	}
	positionShift = -1;
	positionStep = -0.08;
	WHICH_WAY = RunnableGetImage.MOVE_UP;
	(kicker = new Thread(this)).start();
	kicker.join();
}

public synchronized void moveDown() throws InterruptedException {
	
	begin=false;
	if (checkWallCollision(this, this.getMap().getPlayer(),
	        BOTTOM_COLLISION)) {
		begin=true;
	    return;
	}
	if (checkBagCollision(this, BOTTOM_COLLISION)){
		begin=true;
		return;
	}
	positionShift = 1;
	positionStep = 0.08;
	WHICH_WAY = RunnableGetImage.MOVE_DOWN;
	
	(kicker = new Thread(this)).start();
	kicker.join();
}

public synchronized void moveRight() throws InterruptedException{
	
	begin=false;
	if (checkWallCollision(this, this.getMap().getPlayer(),
	        RIGHT_COLLISION)) {
		begin=true;
	    return;
	}
	if (checkBagCollision(this, RIGHT_COLLISION)){
		begin=true;
		return;
	}
	positionShift = 1;
	positionStep = 0.08;
	WHICH_WAY = RunnableGetImage.MOVE_RIGHT;
	
	(kicker = new Thread(this)).start();
	kicker.join();
}

public synchronized void moveLeft() throws InterruptedException{
	
	begin=false;
	if (checkWallCollision(this, this.getMap().getPlayer(),
	        LEFT_COLLISION)) {
		begin=true;
	    return;
	}
	if (checkBagCollision(this, LEFT_COLLISION)){
		begin=true;
		return;
	}
	positionShift = -1;
	positionStep = -0.08;
	WHICH_WAY = RunnableGetImage.MOVE_LEFT;
	
	(kicker = new Thread(this)).start();
	kicker.join();
}





private static boolean checkWallCollision(RunnableGetImage Board, MovingImage actor, int type) {

	if (type == LEFT_COLLISION) {

        for (int i = 0; i < Board.getMap().getWalls().size(); i++) {
            //Wall wall = (Wall) walls.get(i);
            if (actor.isLeftCollision((MovingImage)Board.getMap().getWalls().get(i))) {
                return true;
            }
        }
        return false;

    } else if (type == RIGHT_COLLISION) {

        for (int i = 0; i < Board.getMap().getWalls().size(); i++) {
            //Wall wall = (Wall) walls.get(i);
            if (actor.isRightCollision((MovingImage)Board.getMap().getWalls().get(i))) {
                return true;
            }
        }
        return false;

    } else if (type == TOP_COLLISION) {

        for (int i = 0; i < Board.getMap().getWalls().size(); i++) {
            //Wall wall = (Wall) walls.get(i);
            if (actor.isTopCollision((MovingImage)Board.getMap().getWalls().get(i))) {
                return true;
            }
        }
        return false;

    } else if (type == BOTTOM_COLLISION) {

    	for (int i = 0; i < Board.getMap().getWalls().size(); i++) {
            //Wall wall = (Wall) walls.get(i);
            if (actor.isBottomCollision((MovingImage)Board.getMap().getWalls().get(i))) {
                return true;
            }
        }
        return false;
    }
    return false;
} 

private boolean checkBagCollision(RunnableGetImage Board, int type) {

	MovingImage player = Board.getMap().getPlayer();
	ArrayList boulders = Board.getMap().getBoulders();
	boulderToMove=-1;
	
	 if (type == TOP_COLLISION) {

	        for (int i = 0; i < boulders.size(); i++) {

	            MovingImage boulder = (MovingImage) boulders.get(i);
	            if (player.isTopCollision(boulder)) {

	                for (int j=0; j < boulders.size(); j++) {
	                    MovingImage item = (MovingImage) boulders.get(j);
	                    if (!boulder.equals(item)) {
	                        if (boulder.isTopCollision(item)) {
	                            return true;
	                        }
	                    }
	                    if (checkWallCollision(Board, boulder,
	                            TOP_COLLISION)) {
	                        return true;
	                    }
	                }
	                
	                boulderToMove=i;
	                return false;
	                //isCompleted();
	            }
	        }
	        
	    }
	 
	 if (type == BOTTOM_COLLISION) {

	        for (int i = 0; i < boulders.size(); i++) {

	            MovingImage boulder = (MovingImage) boulders.get(i);
	            if (player.isBottomCollision(boulder)) {

	                for (int j=0; j < boulders.size(); j++) {
	                    MovingImage item = (MovingImage) boulders.get(j);
	                    if (!boulder.equals(item)) {
	                        if (boulder.isBottomCollision(item)) {
	                            return true;
	                        }
	                    }
	                    if (checkWallCollision(Board, boulder,
	                            BOTTOM_COLLISION)) {
	                        return true;
	                    }
	                }
	                
	                boulderToMove=i;
	                return false;
	                
	            }
	        }
	        
	    }
	 
    if (type == RIGHT_COLLISION) {

        for (int i = 0; i < boulders.size(); i++) {

            MovingImage boulder = (MovingImage) boulders.get(i);
            if (player.isRightCollision(boulder)) {

                for (int j=0; j < boulders.size(); j++) {
                    MovingImage item = (MovingImage) boulders.get(j);
                    if (!boulder.equals(item)) {
                        if (boulder.isRightCollision(item)) {
                            return true;
                        }
                    }
                    if (checkWallCollision(Board, boulder,
                            RIGHT_COLLISION)) {
                        return true;
                    }
                }
                
                boulderToMove=i;
                return false;
              
            }
        }
        
    }
    if (type == LEFT_COLLISION) {

        for (int i = 0; i < boulders.size(); i++) {

            MovingImage boulder = (MovingImage) boulders.get(i);
            if (player.isLeftCollision(boulder)) {

                for (int j=0; j < boulders.size(); j++) {
                    MovingImage item = (MovingImage) boulders.get(j);
                    if (!boulder.equals(item)) {
                        if (boulder.isLeftCollision(item)) {
                            return true;
                        }
                    }
                    if (checkWallCollision(Board, boulder,
                            LEFT_COLLISION)) {
                        return true;
                    }
                }
                
                boulderToMove=i;
                return false;
                //isCompleted();
            }
        }
        
    }
    return false;
    
}
	public void run() {
		
		timeToQuit=false;
		System.out.println("JEstem w runie!");
		if (WHICH_WAY == MOVE_RIGHT | WHICH_WAY == MOVE_LEFT){
			float initialPosition = map.getPlayer().getX();
			do {
	    	    // Prepare for rendering the next frame
	            modifyLocation(initialPosition, WHICH_WAY, positionShift, positionStep, boulderToMove);
	            // Render single frame
	            do {
	            	// The following loop ensures that the contents of the drawing buffer
	            	// are consistent in case the underlying surface was recreated
	            	do {
	            		// Get a new graphics context every time through the loop
	            		// to make sure the strategy is validated
	            		Graphics graphics = bs.getDrawGraphics();
	            		updateOffscreen(graphics);
	            		//repaint((int)(initialPosition)*TILE_SIZE, (int)(map.getPlayer().getY())*TILE_SIZE, 3*64, 64);//updateOffscreen(graphics);// Render to graphics sprobowac repaintem
	            		graphics.dispose(); // Dispose the graphics

	            		// Repeat the rendering if the drawing buffer contents were restored
	    	         } while (bs.contentsRestored());
	            	// Display the buffer
	            	bs.show();
	            	// Repeat the rendering if the drawing buffer was lost
		     	} while (bs.contentsLost());
	         sleep();
	    	 
	    	} while(!timeToQuit);
			/*if (boulderToMove>-1 ) {
				MovingImage boulder = (MovingImage)map.getBoulders().get(boulderToMove);
				boulder.setX(initialPosition+positionShift+Math.signum(positionShift));
			}
			System.out.println("Final position X: " + positionToPixels(map.getPlayer().getX()));
			System.out.println("Final position Y: " + positionToPixels(map.getPlayer().getY()));
	    	map.getPlayer().setX(initialPosition+positionShift);*/
		
	    
		}
		else if (WHICH_WAY == MOVE_UP | WHICH_WAY == MOVE_DOWN) {
			float initialPosition = map.getPlayer().getY();
			do {
	    	    // Prepare for rendering the next frame
	            modifyLocation(initialPosition, WHICH_WAY, positionShift, positionStep, boulderToMove);
	            // Render single frame
	            do {
	            	// The following loop ensures that the contents of the drawing buffer
	            	// are consistent in case the underlying surface was recreated
	            	do {
	            		// Get a new graphics context every time through the loop
	            		// to make sure the strategy is validated
	            		Graphics graphics = bs.getDrawGraphics();
	            		updateOffscreen(graphics);
	            		//repaint((int)initialPosition*TILE_SIZE, (int)(map.getPlayer().getY())*TILE_SIZE, 64, 64);//updateOffscreen(graphics);// Render to graphics sprobowac repaintem
	            		graphics.dispose(); // Dispose the graphics

	            		// Repeat the rendering if the drawing buffer contents were restored
	    	         } while (bs.contentsRestored());
	            	// Display the buffer
	            	bs.show();
	            	// Repeat the rendering if the drawing buffer was lost
		     	} while (bs.contentsLost());
	         sleep();
	    	 
	    	} while(!timeToQuit);
			/*if (boulderToMove>-1 ) {
				MovingImage boulder = (MovingImage)map.getBoulders().get(boulderToMove);
				boulder.setY(initialPosition+positionShift+Math.signum(positionShift));
			}
	    	map.getPlayer().setY(initialPosition+positionShift);
	    	System.out.println("Final position X: " + positionToPixels(map.getPlayer().getX()));
	    	System.out.println("Final position Y: " + positionToPixels(map.getPlayer().getY()));*/
			
	    
		}
		/*System.out.println(initialPosition);
    	do {
    	    // Prepare for rendering the next frame
            modifyLocation(initialPosition);
            // Render single frame
            do {
            	// The following loop ensures that the contents of the drawing buffer
            	// are consistent in case the underlying surface was recreated
            	do {
            		// Get a new graphics context every time through the loop
            		// to make sure the strategy is validated
            		Graphics graphics = bs.getDrawGraphics();
            		updateOffscreen(graphics);
            		//repaint((int)initialPosition*TILE_SIZE, (int)(map.getPlayer().getY())*TILE_SIZE, 64, 64);//updateOffscreen(graphics);// Render to graphics sprobowac repaintem
            		graphics.dispose(); // Dispose the graphics

            		// Repeat the rendering if the drawing buffer contents were restored
    	         } while (bs.contentsRestored());
            	// Display the buffer
            	bs.show();
            	// Repeat the rendering if the drawing buffer was lost
	     	} while (bs.contentsLost());
         sleep();
    	 
    	} while(!timeToQuit);
    	map.getPlayer().setY(initialPosition-1);
    	System.out.println(map.getPlayer().getY());*/
		isCompleted();
		System.out.println("Syszedłem z runa");
		if (!begin) System.out.println("Begin jest na false!");
		begin=true;
		if (begin) System.out.println("Ustawilem begin na true");
    }
	
	public int positionToPixels (float position) {
		
		return (int)(position * TILE_SIZE);
		
	}
	
	public int tilesToPixels(int numTiles) {
       
        return numTiles * TILE_SIZE;
        
    }
	
	public void addNotify() {
        super.addNotify();
        createBufferStrategy(2); // argumentem liczba buforów
        bs = getBufferStrategy();
       
    }
	public Dimension getPreferredSize() {
        /*if (map == null) {
             return new Dimension(100,100);
        } else {*/
           return new Dimension(tilesToPixels(map.getWidth()), tilesToPixels(map.getHeight()));
       //}
    }
	
	public TileMap getMap() {
		
		return map;
		
	}
	

	
	public void paint(Graphics g) 
	
		{
			offscr = createImage(getWidth(), getHeight());
			offgr = offscr.getGraphics();
			updateOffscreen(offgr);
			g.drawImage(offscr, 0,0,null);
			System.out.println("Jestem w paint nalezacym do Canvas");
		}
		
		/*if (RunnableMyFrame.gameCompleted)
		{
			int width = getWidth();
			int height = getHeight();
			g.clearRect(0, 0, getWidth(), getHeight());
			g.setColor(new Color(255, 0, 0));
            g.setFont(new Font(Font.DIALOG, getHeight()/20, getHeight()/20));
            FontMetrics fm = getFontMetrics(getFont());
            String text1 = "Zakończyłeś grę. Twój wynik został wpisany do rankingu";
            int fontWidth = fm.stringWidth(text1);
            
            g.drawString(text1,( width-fontWidth )/2, height/2);
            return;
           
		}*/
	
		
		
		
		
		/*else if (completed)
		{
			g.clearRect(0, 0, getWidth(), getHeight());
			g.setColor(new Color(255, 0, 0));
            g.setFont(new Font(Font.DIALOG, getHeight()/20, getHeight()/20));
            FontMetrics fm = getFontMetrics(getFont());
            String text1 = "Wygrałeś! Nacisnij klawisz 'R', aby zrestartowac gre";
            String text2 = "Nacisnij 'N', aby przejść do kolejnego poziomu";
            int width = fm.stringWidth(text1);
            g.drawString(text1,( super.getWidth()-width )/4, super.getHeight()/2);
            width = fm.stringWidth(text2);
            g.drawString(text2,( super.getWidth()-width )/4, super.getHeight()/2+20);
		}*/
		/*else if (RunnableMyFrame.gameFailed)
			{
			
			g.clearRect(0, 0, getWidth(), getHeight());
			g.setColor(new Color(255, 0, 0));
            g.setFont(new Font(Font.DIALOG, getHeight()/20, getHeight()/20));
            FontMetrics fm = getFontMetrics(getFont());
            String text = "Przegrałeś! Naciśnij klawisz 'R', aby zrestartowac grę";
            int width = fm.stringWidth(text);
            g.drawString(text,( super.getWidth()-width )/4, super.getHeight()/2);
            
			}*/
		
		
             /*g.setColor(new Color(255, 0, 0));
             g.setFont(new Font(Font.DIALOG, 50, 50));
             int height = getHeight();
             int width = getWidth();
             g.drawString("Wygrałeś!", width/10, height/2);*/
         
		 /*else if (RunnableMyFrame.endOfGame)
			  {
				 g.setColor(new Color(255, 0, 0));
	             g.setFont(new Font(Font.DIALOG, 50, 50));
	             int height = getHeight();
	             int width = getWidth();
	             g.drawString("Pregrałeś!", width/10, height/18);
			 }*/
		 
		 

			
		 /*for (int y=0; y < map.getHeight(); y++) { 
				
	            for (int x=0; x < map.getWidth(); x++) {
	                
	                
	                	
	                    
	                    	if (map.getTile(x, y)!= null){
	                    	g.drawImage(map.getTile(x,y),
	                    			tilesToPixels(x),
	                    			tilesToPixels(y),
	                    			TILE_SIZE,
	                    			TILE_SIZE,
	                    			null);
	                    	}
	            }
			}
			g.drawImage(map.getPlayerImage(), 
					positionToPixels(map.getPlayer().getX()), 
					positionToPixels(map.getPlayer().getY()),
					TILE_SIZE,
					TILE_SIZE,
					null);
			for (int i=0; i<map.getBoulders().size(); i++)
				
			g.drawImage(map.getBoulderImage(), 
					positionToPixels(((MovingImage)map.getBoulders().get(i)).getX()), 
					positionToPixels(((MovingImage)map.getBoulders().get(i)).getY()),
					TILE_SIZE,
					TILE_SIZE,
					null);*/
		 
	
	public void update(Graphics g) 
	{
		System.out.println("Jestem w update nalezacym do Canvas");
        paint(g);
        
    }
	
	public void isCompleted() {

        int numOfBoulders = map.getBoulders().size();
        int properlySet = 0;

        for (int i = 0; i < numOfBoulders; i++) {
            MovingImage boulder = (MovingImage) map.getBoulders().get(i);
            for (int j = 0; j < numOfBoulders; j++) {
                MovingImage area = (MovingImage) map.getAreas().get(j);
                if (boulder.getX() == area.getX()
                        && boulder.getY() == area.getY()) {
                    properlySet += 1;
                }
            }
        }

        if (properlySet == numOfBoulders) {
            completed = true;
            repaint();
        }
    }

	
}	                            
		                            
		                            
                    	
	                    	
	                    
	      

